package code12线程;

/**
 * @author 黄衡熙
 * @version 1.0
 */
public class Test09_生产者消费者问题 {
    public static void main(String[] args) {
        ProductPool pool = new ProductPool();
        // 定义生产者
        Producer p1 = new Producer(pool, "生产者p1");
        Producer p2 = new Producer(pool, "生产者p2");
        Producer p3 = new Producer(pool, "生产者p3");
        // 定义消费者
        Consumer c1 = new Consumer(pool, "消费者c1");
        Consumer c2 = new Consumer(pool, "消费者c2");
        // 启动线程
        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
    }

}

// 缓冲区:商品池
class ProductPool {
    // 当前缓冲区中商品数量
    private int num;
    // 当前缓冲区中商品数量的上限,固定值,定义为常量
    private static final int MAX_COUNT = 20;
    /**
     * 生产者生产商品之后将商品存放到缓冲区
     * @return
     */
    public int put() {
        // 每调用一次方法,说明生产者生产了一件商品
        num++;
        return num;
    }
    /**
     * 消费者消费商品时从缓冲区中取出商品
     * @return
     */
    public int get() {
        // 每调用一次方法,说明消费者消费了一件商品
        num--;
        return num;
    }
    /**
     * 判断缓冲区中商品数量是否已经达到了上限
     * @return
     */
    public boolean isFull() {
        return this.num == MAX_COUNT;
    }
    /**
     * 判断缓冲区中商品是否为空
     * @return
     */
    public boolean isEmpty() {
        return this.num == 0;
    }
}

//生产者
class Producer extends Thread {
    private ProductPool pool;
    private String name;
    public Producer(ProductPool pool, String name) {
        this.pool = pool;
        this.name = name;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (pool) {
                // 判断当前缓冲区中商品数量是否已经达到了上限
                if (pool.isFull()) {
                    try {
                        // 如果商品达到了上限,则停止生产,等待消费者进行消费
                        System.out.println("当前缓冲区中商品已满,需要等待消费者进行消费");
                        pool.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    // 如果没有达到上限,则生产商品
                    int num = pool.put();
                    System.out.println(this.name + "生产了一件商品,当前缓冲区中商品数量为:" + num);
                    // 生产了商品之后,需要将等待消费的消费者全部唤醒
                    pool.notifyAll();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
//消费者
class Consumer extends Thread {
    private ProductPool pool;
    private String name;
    public Consumer(ProductPool pool, String name) {
        this.pool = pool;
        this.name = name;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (pool) {
                // 判断当前缓冲区中商品是否为空
                if (pool.isEmpty()) {
                    try {
                        // 如果为空,则需要等待生产者进行生产
                        System.out.println("当前缓冲区中没有商品,需要等待生产者进行生产");
                        pool.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    // 如果不为空,则消费者消费商品
                    int num = pool.get();
                    System.out.println(this.name + "消费了一件商品,当前缓冲区中商品数量为:" + num);
                    // 当消费者消费了之后,需要将等待的生产者全部唤醒
                    pool.notifyAll();
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
